/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#ifndef UNIFORMNOISEGENERATOR_H
#define UNIFORMNOISEGENERATOR_H

// Używamy generatorów z biblioteki boost.
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/normal_distribution.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/uniform_real_distribution.hpp>

#include <ctime>
#include <numeric>

/**
    Klasa opakowująca generator liczb losowych.

    Zawiera generator liczb losowych o rozkładzie równomiernym.
    Domyślnie generuje liczby z przedziału <-1.0, 1.0>, przy czyn
    można podać mnożnik, który zwiększa zakres liczb losowych.

    Ziarno generatora zostaje utworzone na podstawie czasu powołania
    obiektu do życia.
  */
class UniformNoiseGenerator
{
public:

    /**
        Tworzy obiekt generatora losowego.
        Domyślna wariancja (a raczej wzmocnienie) szumu wynosi 1.

        \param [in] gain Wzmocnienie szumu losowego.
    */
    explicit UniformNoiseGenerator(double gain = 1)
        : m_dst(boost::random::normal_distribution<>(0, gain)), m_gain(gain)
    {
        m_rng.seed(time(0));
    }

    /**
        Zwraca kolejną wartość szumu losowego.
    */
    double getNextValue()
    {
        return m_dst(m_rng);
    }

    /**
        Zwraca wzmocnienie sygnału szumu.
    */
    double getGain() const { return m_gain; }

    /**
        Ustawia wzmocnie sygnału szumu.
        \param [in] gain Wzmocnienie.
    */
    void setGain(double gain) {
                                m_gain = std::abs(gain);
                                m_dst = boost::random::normal_distribution<>(0, m_gain);
                              }

    /**
        Operator funkcyjny zwracający nową próbkę szumu.
        Działa identycznie jak getNextValue.
    */
    double operator ()()
    {
        return m_dst(m_rng);
    }

private:
    boost::random::mt19937 m_rng;                       ///< Obiekt generatora
    boost::random::normal_distribution<> m_dst; ///< Obiekt rozkładu prawdopodobieństwa.

    double m_gain;
};

#endif // UNIFORMNOISEGENERATOR_H
